package com.zyx.concurrentdemo.c06cas;

import com.zyx.concurrentdemo.c02basic.util.Sleeper;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicMarkableReference;

/**
 * @author Yaxi.Zhang
 * @since 2021/10/18 10:58
 * desc: 基于 AtomicMarkableReference 解决ABA问题
 */
@SuppressWarnings("AlibabaAvoidManuallyCreateThread")
@Slf4j(topic = "c.TestAbaAtomicMarkableReference")
public class TestAbaAtomicMarkableReference {

    public static void main(String[] args) {
        GarbageBag bag = new GarbageBag("装满的垃圾袋...");
        // 参数2 mark 可以看作一个标记, true表示垃圾袋满了
        AtomicMarkableReference<GarbageBag> ref = new AtomicMarkableReference<>(bag, true);
        log.debug("start");
        log.debug("垃圾袋:{}", ref.getReference());
        Sleeper.sleep(1);
        new Thread(() -> {
            log.debug("保洁阿姨清空垃圾带");
            // 仍然使用当前垃圾带, 将装满状态清空
            log.debug("清理成功? {}", ref.compareAndSet(bag, bag, true, false));
            log.debug("垃圾袋:{}", ref.getReference());
        }, "保洁阿姨").start();

        Sleeper.sleep(1);

        // 只有在垃圾袋满的标志(expectedMark)为true时才会尝试换新的垃圾袋, 但由于保洁阿姨已经清理并将标志设为false, 因此不会更换垃圾袋
        log.debug("是否需要更换垃圾袋? {}", ref.compareAndSet(bag, new GarbageBag("空的垃圾袋"), true, false));
        log.debug("垃圾袋:{}", ref.getReference());
    }
}

class GarbageBag {
    String desc;

    public GarbageBag(String desc) {
        this.desc = desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return super.toString() + " " + desc;
    }
}
